package com.example.store;

import com.example.model.Device;
import com.example.service.Tenant;
import com.example.service.TenantAwareDataSourceFactory;
import org.apache.ignite.cache.store.CacheStoreAdapter;
import org.apache.ignite.lang.IgniteBiInClosure;
import javax.cache.Cache;
import javax.cache.integration.CacheWriterException;
import javax.sql.DataSource;
import java.sql.*;
import java.util.Calendar;

/**
 * 自定义CacheStore
 * 不使用CacheJdbcPojoStore时，可以自定义CacheStore
 */
public class DeviceCacheStore extends CacheStoreAdapter<Long, Device> {
//    private final transient DataSource dataSource;
    private final Tenant tenant;

    public DeviceCacheStore( Tenant tenant) {
//        this.dataSource = dataSource;
        this.tenant = tenant;
    }

    private DataSource getDataSource(){
        return new TenantAwareDataSourceFactory(tenant).create();
    }

    @Override
    public Device load(Long key) {
        try (Connection conn = getDataSource().getConnection()) {
            try (PreparedStatement st = conn.prepareStatement(
                    "SELECT * FROM " + tenant.getSchema() + ".device WHERE id = ?")) {
                st.setLong(1, key);
                ResultSet rs = st.executeQuery();
                if (rs.next()) {
                    return mapResultSetToDevice(rs);
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    @Override
    public void write(Cache.Entry<? extends Long, ? extends Device> entry) {
        Device device = entry.getValue();
        try (Connection conn = getDataSource().getConnection()) {
            try (PreparedStatement st = conn.prepareStatement(
                    "INSERT INTO " + tenant.getSchema() + ".device (id, serial_number, device_type_id, name, active, create_time) " +
                            "VALUES (?, ?, ?, ?, ?, ?) " +
                            "ON DUPLICATE KEY UPDATE " +
                            "serial_number=?, device_type_id=?, name=?, active=?, create_time=?")) {

                st.setLong(1, device.getId());
                st.setString(2, device.getSerialNumber());
                st.setLong(3, device.getDeviceTypeId());
                st.setString(4, device.getName());
                st.setBoolean(5, device.getActive());
                st.setTimestamp(6, new Timestamp(device.getCreateTime().getTime()));

                st.setString(7, device.getSerialNumber());
                st.setLong(8, device.getDeviceTypeId());
                st.setString(9, device.getName());
                st.setBoolean(10, device.getActive());
                st.setTimestamp(11, new Timestamp(device.getCreateTime().getTime()));

                st.executeUpdate();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void delete(Object key) throws CacheWriterException {

    }

    @Override
    public void loadCache(IgniteBiInClosure<Long, Device> clo, Object... args) {
        try (Connection conn = getDataSource().getConnection()) {
            try (PreparedStatement st = conn.prepareStatement(
                    "SELECT * FROM " + tenant.getSchema() + ".device WHERE create_time >= ?")) {

                Calendar cal = Calendar.getInstance();
                cal.add(Calendar.MONTH, -6);
                st.setTimestamp(1, new Timestamp(cal.getTimeInMillis()));

                ResultSet rs = st.executeQuery();
                while (rs.next()) {
                    Device device = mapResultSetToDevice(rs);
                    clo.apply(device.getId(), device);
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private Device mapResultSetToDevice(ResultSet rs) throws SQLException {
        Device device = new Device();
        device.setId(rs.getLong("id"));
        device.setSerialNumber(rs.getString("serial_number"));
        device.setDeviceTypeId(rs.getLong("device_type_id"));
        device.setName(rs.getString("name"));
        device.setActive(rs.getBoolean("active"));
        device.setCreateTime(rs.getTimestamp("create_time"));
        return device;
    }
}